package isquirrel.recommender;

import isquirrel.beans.Recommendation;
import isquirrel.beans.Url;
import isquirrel.beans.User;
import isquirrel.util.HibernateUtil;
import isquirrel.util.URL;

import java.io.UnsupportedEncodingException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.hibernate.Query;


public abstract class Recommender {
	//public abstract List<Url> getRecommendations(User user, int howMany );
	
	//if it's already liked don't recommend it
	protected boolean isAlreadyLiked( String url){
		return false;
	}
	
	@SuppressWarnings("unchecked")
	public static List<Url> getLikes(User user, int howMany) {
		
		Query q = HibernateUtil
				.getSession()
				.createQuery(
						"from Url where user_id = ? and liked = ? order by title desc")
				.setLong(0, user.getUserID()).setBoolean(1, true);
		if (howMany > -1){
			return q.setMaxResults(howMany).list();
		}
		return q.list();
		
	}
	
	public static void updateUrls(User user, Set<String> newUrls, String source) {

		// add all the new recommendations (the ones that are already there
		// remain there)
//		System.out.println("Initially user has " + user.getUrls().size() + " urls ");
		for (String url : newUrls) {
			Url u = new Url(URL.getTitle(url), url, source);
			// u.setThumb(dbPedia.getThumbnail(url));
			user.addUrl(u);
		}
//		System.out.println("Finally user has " + user.getUrls().size() + " urls ");
		
		//newUrls.clear();

		// remove all urls that do not occur in the new list of recommendations
		// and that are not marked as liked.
		Iterator<Url> itr = user.getUrls().iterator();
		Url url;

		Set<Url> toBeRemoved = new HashSet<Url>(); // Using this set to avoid
													// the
													// ConcurrentModificationException
		while (itr.hasNext()) {
			url = itr.next();
			if (url.getSource() != null &&  url.getSource().equals(source) && !url.isLiked()
					&& !newUrls.contains(url.getAddress())) {
				toBeRemoved.add(url);
			}
		}
//		System.out.println("Removing " + toBeRemoved.size() + " old urls ");
		user.getUrls().removeAll(toBeRemoved);
		
		HibernateUtil.getSession().saveOrUpdate(user);

	}
	
	@SuppressWarnings("unchecked")
	public static List<Recommendation> getRecommendations(User user,
			boolean liked, int howMany, String source, boolean getAbstract) throws UnsupportedEncodingException {
		//fetch all recommendations
		List<Url> recs = HibernateUtil
				.getSession()
				.createQuery(
						"from Url where user_id = ? and liked = ? and source= ? order by recommended asc")
				.setLong(0, user.getUserID()).setBoolean(1, liked).setString(2, source)
				.list();
	
		return getRandomRecommendations(recs, howMany, getAbstract);
	}
	
	public static List<Recommendation> getRandomRecommendations(List<Url> recs, int howMany,boolean getAbstract) throws UnsupportedEncodingException {

		List<Recommendation> recommendations = new LinkedList<Recommendation>();
		
		//randomly pick a recommendation from the recs list (and remove it from the list)
		for (int i = 0; i < howMany; i++) {
			int r = getRandomNumber(0, recs.size()-1);
			if (r < recs.size()) {
				Url u = recs.remove(r);
				u.setRecommended(u.getRecommended()+1);
				recommendations.add(new Recommendation(u.getAddress(), getAbstract));
			}
		}
		
		return recommendations;
	}
	
	public static int getRandomNumber(int from, int to) {
		if (to <= from+1) {
			return from;
		}
		int diff = (int) Math.ceil((to-from)/2);
		if (Math.random() < 0.6) {
			return getRandomNumber(from,to-diff);
		} else {
			return getRandomNumber(from+diff,to);
		}
	}
	
	public static Url getUrl(long uid, String address){
		return (Url) HibernateUtil
			         .getSession()
		             .createQuery(
				                  "from Url where user_id = ? and address = ?")
			         .setLong(0,uid).setString(1, address).uniqueResult();
	}
}
